////////////////////////////////////////////////////////////////////
// File:	Interpolator.h
// Purpose: Interpolates a specified "instanced" animation from it's 
//			bind pose to it's current animation specified. Used as a 
//			media player for the animation (play, stop, pause.)
// Author:	Jay Baird
////////////////////////////////////////////////////////////////////

#ifndef INTERPOLATOR_H
#define INTERPOLATOR_H

#include "Animation.h"
#include "MeshComponents.h"
#include "AnimationComponents.h"
#include "Mesh.h"
#include <map>

class Interpolator
{
private:
	unsigned m_loopCount;
	unsigned m_currFrameIndex;	// What's the index of the currentKeyFrame?
	unsigned m_bindFrameIndex;
	int m_meshID;
	int m_animationID;
	int m_bindPoseID;
	bool m_bIsPaused;
	float m_currentTime;
	Animation* m_pAnimation;	// instance of the animation we are interpolating through from the AnimationManager
	Animation* m_pBindPose;		// instance of a animation that is in a bind pose meaning every animation will start from this
	AnimationComponent::KeyFrame m_currKeyFrame;
	std::vector<vec3> m_weightedVerts; // new pointer to vertices created from interpolated influences and weights

	std::vector<std::vector<vec3>> m_bindTable;	// look up table for inverse bind pose bones

	void MapWeightedVertices(int meshID, unsigned numInfluences) const;

public:
	Interpolator();
	~Interpolator();

	// Sets the animation the interpolator is looking at currently and stepping thru
	// Ins: (id): animation ID
	// Outs: None
	// Return: true if correctly set, false if not
	bool SetAnimation(int id);

	// Sets the animation the interpolator is looking at currently and stepping thru
	// This should only be called at an initialization stage!
	// This function generates a LUT (look up table) for the inverse bindPose bones
	// Ins: (id): bind pose animation ID
	//		(bindFrameIndex): the index of the keyframe for the bind pose
	//		(meshID): the mesh ID that the bind pose is attached to
	// Outs: None
	// Return: true if correctly set, false if not
	bool SetBindPose(int id, unsigned bindFrameIndex, int meshID);

	// Plays an animation according to its step time
	// Ins: (fTimeStep): delta time
	// Outs: None
	// Return: true if played correctly, false if not
	bool Process(float fTimeStep);

	// Pauses an animation in it's tracks
	// Ins: (bIsPaused): true to pause, false to resume
	// Outs: None
	// Return: None
	void Pause(bool bIsPaused) { m_bIsPaused = bIsPaused; }

	// Tests to see if the animation is done playing on the current loop
	bool IsDonePlaying() 
	{ 
		if(!m_pAnimation) return false; 
		return (m_currFrameIndex >= (unsigned)m_pAnimation->m_keyFrames.size() - 1);
	}

	unsigned GetLoopCount() const { return m_loopCount; }
	float GetCurrentTime() const { return m_currentTime; }
	int GetMeshID() const { return m_meshID; }
	int GetAnimationID() const { return m_animationID; }
	int GetBindPoseID() const { return m_bindPoseID; }
	unsigned GetBindFrameIndex() const { return m_bindFrameIndex; }
	unsigned GetCurrFrameIndex() const { return m_currFrameIndex; }
	const AnimationComponent::KeyFrame& GetCurrentKeyFrame() { return m_currKeyFrame; }
	void SetTime(float time) { m_currentTime = time; }

};

#endif